﻿using System;
using System.Collections.Generic;
//using System.Linq;
using System.Text;
using System.Net.Sockets;
using System.Collections;
using System.Threading;
using System.IO;
using System.Windows.Forms;
using System.Data;

namespace Server
{
    public class ClientProgram
    {
        #region -  VARIABLES  -
        private TcpClient client = null;
        private NetworkStream ns = null;
        public Queue sendQueue = null;
        private FileStream fs = null;
        private string filePath = null;//
        private MyMessage message = null;
        private DataPackage package = null;
        private ProgressBar progressBar = null;
        private ViewClientDesktop viewDesktopClient = null;
        private ViewListProcesses viewListProcesses = null;
        private bool messageShow = false;
        private bool progressBarShow = false;
        private bool viewDesktopClientShow = false;
        public bool isExit = false;
        private bool isSendFile = true;
        private bool isViewListProcesses = false;
        public List<string> listdenyprogram;
        private List_Deny_Program l = null;
        #endregion

        #region -  THREADS  -
        private Thread tSendThread = null;
        private Thread tReceiveThread = null;
        #endregion

        #region -  EVENTS  -
        public event SendFilenameEventHandler OnSendFilename = null;
        public event SendFilePercentEventHandler OnSendFilePercent = null;
        public event ReceiveFilenameEventHandler OnReceiveFilename = null;
        public event ReceiveFilePercentEventHandler OnReceiveFilePercent = null;
        public event ReceiveMessageEventHandler OnReceiveMessage = null;
        public event ViewDesktopClientEventHandler OnViewDesktopClient = null;
        public event USBDetectedEventHandler OnUSBDetected = null;
        public event GetListProcessesEventHandler OnGetListProcesses = null;
        public event AttendenceCheckEventHandler OnAttendenceCheck = null;
        public event ClientExitEventHandler OnClientExit = null;
        #endregion

        #region -  CONTRUCTOR  -
        public ClientProgram(TcpClient client)
        {
            this.filePath = AccessConfigFile.ReadFile("SaveFileToDirectory.conf");
            if (this.filePath == null)
                this.filePath = Application.StartupPath;
            this.client = client;
            this.client.ReceiveTimeout = 60000;//Receive Timeout 1 minute
            this.client.SendTimeout = 60000;//Send Timeout 1 minute
            this.ns = this.client.GetStream();
            this.sendQueue = new Queue();
            this.tSendThread = new Thread(new ThreadStart(Send));
            this.tSendThread.Priority = ThreadPriority.Lowest;
            this.tSendThread.Start();
            this.tReceiveThread = new Thread(new ThreadStart(Receive));
            this.tReceiveThread.Priority = ThreadPriority.Lowest;
            this.tReceiveThread.Start();
            this.SetMessageBox(this.GetIPAddress());
            this.isExit = false;
            this.listdenyprogram = new List<string>();
        }
        #endregion

        #region -  SEND  -
        public void Send()
        {
            try
            {
                int totalBytes = 0;
                int currentBytes = 0;
                int readBytes = 0;
                int percent = 0;
                byte[] buffer = null;
                DataPackage package = null;
                while (true)
                {
                    Thread.Sleep(10);
                    if (!this.isSendFile)
                        this.isSendFile = true;
                    while (this.sendQueue.Count > 0)
                    {
                        //Send Package
                        package = new DataPackage();
                        package = (DataPackage)this.sendQueue.Dequeue();
                        buffer = package.ToByteHeader();
                        this.ns.Write(buffer, 0, buffer.Length);
                        this.ns.Flush();
                        switch (package.Cmd)
                        {
                            //Send command
                            case Command.Cmd:
                                while (this.sendQueue.Count == 0)
                                { }
                                CommandType cmdType = (CommandType)this.sendQueue.Dequeue();
                                switch (cmdType)
                                {
                                    case CommandType.Restart:
                                        buffer = BitConverter.GetBytes((int)CommandType.Restart);
                                        this.ns.Write(buffer, 0, 4);
                                        this.ns.Flush();
                                        break;
                                    case CommandType.Shutdown:
                                        buffer = BitConverter.GetBytes((int)CommandType.Shutdown);
                                        this.ns.Write(buffer, 0, 4);
                                        this.ns.Flush();
                                        break;
                                    case CommandType.Standby:
                                        buffer = BitConverter.GetBytes((int)CommandType.Standby);
                                        this.ns.Write(buffer, 0, 4);
                                        this.ns.Flush();
                                        break;
                                    case CommandType.LogOff:
                                        buffer = BitConverter.GetBytes((int)CommandType.LogOff);
                                        this.ns.Write(buffer, 0, 4);
                                        this.ns.Flush();
                                        break;
                                    case CommandType.Hibernate:
                                        buffer = BitConverter.GetBytes((int)CommandType.Hibernate);
                                        this.ns.Write(buffer, 0, 4);
                                        this.ns.Flush();
                                        break;
                                    case CommandType.LockComputer:
                                        buffer = BitConverter.GetBytes((int)CommandType.LockComputer);
                                        this.ns.Write(buffer, 0, 4);
                                        this.ns.Flush();
                                        break;
                                    case CommandType.ViewClientDesktop:
                                        buffer = BitConverter.GetBytes((int)CommandType.ViewClientDesktop);
                                        this.ns.Write(buffer, 0, 4);
                                        this.ns.Flush();
                                        break;
                                    case CommandType.AttendenceCheck:
                                        buffer = BitConverter.GetBytes((int)CommandType.AttendenceCheck);
                                        this.ns.Write(buffer, 0, 4);
                                        this.ns.Flush();
                                        break;
                                    case CommandType.GetListProcess:
                                        buffer = BitConverter.GetBytes((int)CommandType.GetListProcess);
                                        this.ns.Write(buffer, 0, 4);
                                        this.ns.Flush();
                                        break;
                                    case CommandType.DenyProcess:
                                        buffer = BitConverter.GetBytes((int)CommandType.DenyProcess);
                                        this.ns.Write(buffer, 0, 4);
                                        this.ns.Flush();
                                        while (this.sendQueue.Count == 0) { }
                                        buffer = Encoding.ASCII.GetBytes(this.sendQueue.Dequeue().ToString());
                                        this.ns.Write(buffer, 0, buffer.Length);
                                        this.ns.Flush();
                                        break;
                                    case CommandType.KillProcess:
                                        buffer = BitConverter.GetBytes((int)CommandType.KillProcess);
                                        this.ns.Write(buffer, 0, 4);
                                        this.ns.Flush();
                                        while (this.sendQueue.Count == 0) { }
                                        buffer = Encoding.ASCII.GetBytes(this.sendQueue.Dequeue().ToString());
                                        this.ns.Write(buffer, 0, buffer.Length);
                                        this.ns.Flush();
                                        break;
                                    case CommandType.StopGetListProcess:
                                        buffer = BitConverter.GetBytes((int)CommandType.StopGetListProcess);
                                        this.ns.Write(buffer, 0, 4);
                                        this.ns.Flush();
                                        break;
                                }
                                break;
                            case Command.Data:
                                if (this.OnSendFilename != null)
                                {
                                    this.OnSendFilename(this, new FilenameEventArgs(this.filePath, this.GetIPAddress()));
                                }
                                this.fs = new FileStream(this.filePath, FileMode.Open, FileAccess.Read);
                                currentBytes = 0;
                                totalBytes = (int)this.fs.Length;
                                while (currentBytes < totalBytes && this.isSendFile)
                                {
                                    buffer = new byte[1024];
                                    readBytes = this.fs.Read(buffer, 0, buffer.Length);
                                    this.ns.Write(buffer, 0, readBytes);
                                    currentBytes += readBytes;
                                    percent = (int)(Math.Round(((double)currentBytes / (double)totalBytes) * 100, 1));
                                    if (this.OnSendFilePercent != null)
                                    {
                                        this.OnSendFilePercent(this, new PercentEventArgs(percent));
                                    }
                                }
                                break;
                            case Command.Text:
                                while (this.sendQueue.Count == 0)
                                { }
                                buffer = Encoding.UTF8.GetBytes(this.sendQueue.Dequeue().ToString());
                                this.ns.Write(buffer, 0, buffer.Length);
                                this.ns.Flush();
                                break;
                            case Command.USBDectect:
                                break;
                        }
                    }
                }
            }
            catch
            {
            }
        }
        #endregion

        #region -  RECEIVE  -
        public void Receive()
        {
            try
            {
                int totalBytes = 0;
                int currentBytes = 0;
                int percent = 0;
                int receiveBytes = 0;
                byte[] buffer = null;
                byte[] temp = null;
                string mess = null;
                string[] listProcesses = null;
                DataPackage package = null;
                FileInfo fileInfo = null;
                while (true)
                {
                    Thread.Sleep(10);
                    buffer = new byte[1024];
                    receiveBytes = this.ns.Read(buffer, 0, buffer.Length);
                    if (receiveBytes == 0)
                    {
                        if (this.OnClientExit != null)
                        {
                            this.OnClientExit(this, new ClientExitEventArgs(this.GetIPAddress()));
                        }
                        this.isExit = true;
                        this.StopClient();
                        break;
                    }
                    temp = new byte[receiveBytes];
                    Array.Copy(buffer, 0, temp, 0, receiveBytes);
                    package = new DataPackage();
                    package.PackageHeader(temp);
                    switch (package.Cmd)
                    {
                        case Command.Cmd:
                            buffer = new byte[4];
                            this.ns.Read(buffer, 0, 4);
                            this.ns.Flush();
                            CommandType cmdType = (CommandType)BitConverter.ToInt32(buffer, 0);
                            switch (cmdType)
                            {
                                case CommandType.ViewClientDesktop:
                                    buffer = new byte[package.DataLength];
                                    byte[] t = new byte[package.DataLength];
                                    currentBytes = ns.Read(t, 0, t.Length);
                                    totalBytes = currentBytes;
                                    Array.Copy(t, 0, buffer, 0, currentBytes);
                                    while (totalBytes < package.DataLength)
                                    {
                                        t = new byte[package.DataLength - totalBytes];
                                        currentBytes = ns.Read(t, 0, t.Length);
                                        Array.Copy(t, 0, buffer, totalBytes, currentBytes);
                                        totalBytes += currentBytes;
                                    }
                                    if (this.OnViewDesktopClient != null)
                                    {
                                        this.OnViewDesktopClient(this, new ViewDesktopClientEventsArgs(buffer));
                                    }
                                    break;
                                case CommandType.GetListProcess:
                                    buffer = new byte[package.DataLength];
                                    this.ns.Read(buffer, 0, buffer.Length);
                                    mess = Encoding.ASCII.GetString(buffer, 0, buffer.Length);
                                    listProcesses = mess.Split('|');
                                    if (this.OnGetListProcesses != null)
                                    {
                                        this.OnGetListProcesses(this, new GetListProcessesEventArgs(listProcesses));
                                    }
                                    break;
                                case CommandType.AttendenceCheck:
                                    buffer = new byte[100];
                                    receiveBytes = this.ns.Read(buffer, 0, 100);
                                    this.ns.Flush();
                                    temp = new byte[receiveBytes];
                                    Array.Copy(buffer, 0, temp, 0, receiveBytes);
                                    mess = Encoding.UTF8.GetString(temp, 0, receiveBytes);
                                    if (this.OnAttendenceCheck != null)
                                    {
                                        this.OnAttendenceCheck(this, new AttendenceCheckEventArgs(mess));
                                    }
                                    break;
                                case CommandType.DenyProcess:
                                    buffer = BitConverter.GetBytes((int)CommandType.DenyProcess);
                                    this.ns.Write(buffer, 0, 4);
                                    this.ns.Flush();
                                    while (this.sendQueue.Count == 0) { }
                                    buffer = Encoding.ASCII.GetBytes(this.sendQueue.Dequeue().ToString());
                                    this.ns.Write(buffer, 0, buffer.Length);
                                    this.ns.Flush();
                                    break;
                                case CommandType.UnDenyProcess:
                                    buffer = BitConverter.GetBytes((int)CommandType.UnDenyProcess);
                                    this.ns.Write(buffer, 0, 4);
                                    this.ns.Flush();
                                    while (this.sendQueue.Count == 0) { }
                                    buffer = Encoding.ASCII.GetBytes(this.sendQueue.Dequeue().ToString());
                                    this.ns.Write(buffer, 0, buffer.Length);
                                    this.ns.Flush();
                                    break;
                            }
                            break;
                        case Command.Data:
                            try
                            {
                                if (this.OnReceiveFilename != null)
                                {
                                    this.OnReceiveFilename(this, new FilenameEventArgs(package.Filename, this.GetIPAddress()));
                                }
                                totalBytes = package.DataLength;
                                currentBytes = 0;
                                this.fs = new FileStream(this.filePath + @"\" + package.Filename, FileMode.Create, FileAccess.Write);
                                while (currentBytes < totalBytes)
                                {
                                    buffer = new byte[1024];
                                    receiveBytes = this.ns.Read(buffer, 0, 1024);
                                    this.ns.Flush();
                                    this.fs.Write(buffer, 0, receiveBytes);
                                    this.fs.Flush();
                                    currentBytes += receiveBytes;
                                    percent = (int)(Math.Round(((double)currentBytes / (double)totalBytes) * 100, 1));
                                    if (this.OnReceiveFilePercent != null)
                                    {
                                        this.OnReceiveFilePercent(this, new PercentEventArgs(percent));
                                    }
                                }
                            }
                            catch
                            {
                                if (this.progressBar != null)
                                {
                                    this.progressBar.Close();
                                }
                                MessageBox.Show("Lỗi nhận file " + package.Filename + " từ máy trạm.", "Thông Báo",
                                     MessageBoxButtons.OK, MessageBoxIcon.Error);
                                if (this.fs != null)
                                {
                                    this.fs.Flush();
                                    this.fs.Close();
                                    this.fs.Dispose();
                                }
                                fileInfo = new FileInfo(this.filePath + @"\" + package.Filename);
                                if (fileInfo.Exists)
                                {
                                    fileInfo.Delete();
                                }
                            }
                            break;
                        case Command.Text:
                            buffer = new byte[package.DataLength];
                            this.ns.Read(buffer, 0, buffer.Length);
                            this.ns.Flush();
                            mess = Encoding.UTF8.GetString(buffer, 0, buffer.Length);
                            if (this.OnReceiveMessage != null)
                            {
                                this.OnReceiveMessage(this, new MessageEventArgs(mess, this.GetIPAddress()));
                            }
                            break;
                        case Command.USBDectect:
                            if (this.OnUSBDetected != null)
                            {
                                this.OnUSBDetected(this, new USBDetectedEventArgs());
                            }
                            break;

                    }
                }
            }
            catch
            {
            }
        }
        #endregion

        #region -  STOP CLIENT  -
        public void StopClient()
        {
            try
            {
                this.isExit = true;
                this.client.Close();
                Thread.Sleep(500);
                if (this.tSendThread != null)
                {
                    this.tSendThread.Abort();
                }
                if (this.tReceiveThread != null)
                {
                    this.tReceiveThread.Abort();
                }
            }
            catch
            {
            }
        }

        public void StopClient1()
        {
            try
            {
                this.client.Close();
                Thread.Sleep(500);
                if (this.tSendThread != null && this.tSendThread.IsAlive)
                {
                    this.tSendThread.Abort();
                }
                if (this.tReceiveThread != null && this.tReceiveThread.IsAlive)
                {
                    this.tReceiveThread.Abort();
                }
            }
            catch
            {
            }
        }
        #endregion

        #region -  SET LIST PROCESSES  -
        public void SetViewListProcesses()
        {
            if (this.viewListProcesses == null)
            {
                //Instance View List Process
                this.viewListProcesses = new ViewListProcesses();
                this.viewListProcesses.OnKillProcess += new KillProcessEventHandler(viewListProcesses_OnKillProcess);
                this.viewListProcesses.OnFormExit += new FormExitEventHandler(viewListProcesses_OnFormExit);
            }
        }

        void viewListProcesses_OnKillProcess(object sender, ProcessEventArgs e)
        {
            this.package = new DataPackage(Command.Cmd, null, 4);
            this.sendQueue.Enqueue(this.package);
            this.sendQueue.Enqueue(CommandType.KillProcess);
            this.sendQueue.Enqueue(e.Name);
        }

        public void SetListProcessesData(string id, string name, string memory)
        {
            this.viewListProcesses.SetListProcesses(id, name, memory);
        }

        public void SetReload()
        {
            this.viewListProcesses.isReload = true;
        }

        void viewListProcesses_OnFormExit(object sender, FormExitEvenArgs e)
        {
            this.isViewListProcesses = false;
            this.viewListProcesses = null;
            this.package = new DataPackage(Command.Cmd, null, 4);
            this.sendQueue.Enqueue(this.package);
            this.sendQueue.Enqueue(CommandType.StopGetListProcess);
        }

        public void ShowListProcesses()
        {
            if (this.viewListProcesses != null && !this.isViewListProcesses)
            {
                this.isViewListProcesses = true;
                Application.Run(this.viewListProcesses);
            }
        }

        public void ShowListProcesses1()
        {
            if (this.viewListProcesses != null && !this.isViewListProcesses)
            {
                this.isViewListProcesses = true;
                this.viewListProcesses.Show();
            }
        }
        #endregion

        #region -  SET MESSAGE BOX  -
        public void SetMessageBox(string ipAddress)
        {
            try
            {
                if (this.message == null)
                {
                    this.message = new MyMessage();
                    this.message.OnSendMessage += new SendMessageEventHandler(message_OnSendMessage);
                    this.message.OnFormExit += new FormExitEventHandler(message_OnFormExit);
                    this.message.Text = "Khung chat : " + ipAddress;
                    this.message.IpAddress = this.GetIPAddress();
                }
            }
            catch
            { }
        }

        public void SetMessage(string mess)
        {
            this.message.SetMessage(mess);
        }

        void message_OnFormExit(object sender, FormExitEvenArgs e)
        {
            this.message = null;
            this.messageShow = false;
        }

        void message_OnSendMessage(object sender, MessageEventArgs e)
        {
            this.package = new DataPackage(Command.Text, null, e.Message.Length);
            this.sendQueue.Enqueue(this.package);
            this.sendQueue.Enqueue(e.Message);
        }

        public void ShowMessageBox()
        {
            if (this.message != null && !this.messageShow)
            {
                this.messageShow = true;
                Application.Run(this.message);
            }
        }

        public void ShowMessageBox1()
        {
            if (this.message != null && !this.messageShow)
            {
                this.messageShow = true;
                this.message.Show();
            }
        }
        #endregion

        #region -  SET PROGRESS BAR  -
        public void SetProgressBar()
        {
            if (this.progressBar == null)
            {
                //Instance Progress bar
                this.progressBar = new ProgressBar();
                this.progressBar.OnFormExit += new FormExitEventHandler(progressBar_OnFormExit);
                this.progressBar.OnStopSendFile += new StopSendFileEventHandler(progressBar_OnStopSendFile);
            }
        }

        void progressBar_OnStopSendFile(object sender, EventArgs e)
        {
            this.isSendFile = false;
        }
        public void SetProgressBarValue(int percent)
        {
            if (this.progressBar != null)
            {
                this.progressBar.SetProgressBarValue(percent);
            }
        }

        public void SetProgressBarMessage(string message)
        {
            if (this.progressBar != null)
            {
                this.progressBar.SetMessage(message);
            }
        }

        public void SetProgressBarTitle(string title)
        {
            if (this.progressBar != null)
            {
                this.progressBar.SetTitle(title);
            }
        }

        public void ShowProgressBar()
        {
            if (this.progressBar != null && !this.progressBarShow)
            {
                this.progressBarShow = true;
                Application.Run(this.progressBar);
            }
        }

        void progressBar_OnFormExit(object sender, FormExitEvenArgs e)
        {
            this.progressBar = null;
            this.progressBarShow = false;
        }
        #endregion

        #region -  SET VIEW DESKTOP CLIENT  -
        public void SetViewDesktopClient()
        {
            if (this.viewDesktopClient == null)
            {
                //Instance View Desktop Client
                this.viewDesktopClient = new ViewClientDesktop();
                this.viewDesktopClient.OnFormExit += new FormExitEventHandler(viewDesktopClient_OnFormExit);
            }
        }

        public void SetViewDesktopClientData(byte[] data)
        {
            this.viewDesktopClient.SetImage(data);
        }

        public void ShowViewDesktopClient()
        {
            if (this.viewDesktopClient != null && !this.viewDesktopClientShow)
            {
                this.viewDesktopClientShow = true;
                Application.Run(this.viewDesktopClient);
            }
        }

        public void ShowViewDesktopClient1()
        {
            if (this.viewDesktopClient != null && !this.viewDesktopClientShow)
            {
                this.viewDesktopClientShow = true;
                this.viewDesktopClient.Show();
            }
        }

        void viewDesktopClient_OnFormExit(object sender, FormExitEvenArgs e)
        {
            this.viewDesktopClient = null;
            this.viewDesktopClientShow = false;
        }
        #endregion

        #region -  SET FILE PATH  -
        public void SetFilePath(string filePath)
        {
            this.filePath = filePath;
        }
        #endregion

        #region -  GET IP ADDRESS  -
        public string GetIPAddress()
        {
            try
            {
                string ip = this.client.Client.RemoteEndPoint.ToString().Split(':')[0];
                return ip;
            }
            catch
            {
                return null;
            }
        }
        #endregion

        #region -  CONNECTED  -
        public bool Connected()
        {
            try
            {
                return this.client.Connected;
            }
            catch
            {
                return false;
            }
        }
        #endregion


        #region -  DENY PROGRAMS  -
        public void ShowListDenyPro()
        {
            this.l = new List_Deny_Program();
            l.Deny += new DenyProcessEventHandler(l_Deny);
            l.Udeny += new UnDenyProcessEventHandler(l_Udeny);
            l.KT += new KiemTra(l_KT);
            foreach (string i in listdenyprogram)
            {
                l.AddProgram(i);
            }
            l.Show();
        }

        bool l_KT(string s)
        {
            foreach (string i in listdenyprogram)
            {
                if (i.ToLower() == s.ToLower())
                {
                    return false;

                }
            }
            return true;
        }

        void l_Udeny(object sender, ProcessEventArgs e)
        {
            foreach (string i in listdenyprogram)
            {
                if (i == e.Name)
                {
                    listdenyprogram.Remove(i);
                    break;
                }
            }
            this.package = new DataPackage(Command.Cmd, null, 4);
            this.sendQueue.Enqueue(this.package);
            this.sendQueue.Enqueue(CommandType.UnDenyProcess);
            this.sendQueue.Enqueue(e.Name);
        }

        void l_Deny(object sender, ProcessEventArgs e)
        {
            listdenyprogram.Add(e.Name);
            this.package = new DataPackage(Command.Cmd, null, 4);
            this.sendQueue.Enqueue(this.package);
            this.sendQueue.Enqueue(CommandType.DenyProcess);
            this.sendQueue.Enqueue(e.Name);

        }
        #endregion
    }
}



